#ifndef __opengl_video_renderer_hpp
#define __opengl_video_renderer_hpp

#include "p2pms_log.hpp"
#include <webrtc/api/video/video_frame.h>
#include <webrtc/api/video/video_sink_interface.h>
#include <webrtc/api/video/video_track_interface.h>

#include <functional>
#include <mutex>
#include <queue>
#include <thread>
#include <vector>

#ifdef _WIN32
#include <windows.h>
#include <GL/gl.h>
#endif
#ifdef __ANDROID__
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <android/native_window.h>
#endif
#ifdef __APPLE__
#include <OpenGLES/ES3/gl.h>
#include <OpenGLES/ES3/glext.h>
#include <CoreVideo/CVOpenGLESTextureCache.h>
#include <OpenGLES/EAGL.h>
#endif

namespace p2pms {

struct MediaInfo {
    int width = 0;
    int height = 0;
};

class IMainThreadExecutor {
public:
    virtual void PostToMainThread(std::function<void()> task) = 0;
    virtual ~IMainThreadExecutor() = default;
};

struct RenderCommand {
    std::vector<uint8_t> bgra_data;
    int width = 0;
    int height = 0;
    const webrtc::I420BufferInterface* yuv_buffer = nullptr;
    bool use_yuv = true;
#ifdef __ANDROID__
    ANativeWindow* native_buffer = nullptr;
#endif
#ifdef __APPLE__
    CVPixelBufferRef pixel_buffer = nullptr;
#endif
};

class OpenGLVideoRenderer : public webrtc::VideoSinkInterface<webrtc::VideoFrame> {
public:
    OpenGLVideoRenderer(const MediaInfo& media, IMainThreadExecutor* executor);
    ~OpenGLVideoRenderer() override;

#ifdef _WIN32
    bool SetRenderWindow(HWND hwnd);
#else
    bool SetRenderWindow(void* native_window); // ANativeWindow* (Android) or UIView* (iOS)
#endif
    void SetVideoTrack(webrtc::VideoTrackInterface* video_track);
    void OnPaint();
    void OnWindowSizeChanged(int width, int height);
    void Start();
    void Stop();
    void ProcessRenderCommands();

    // WebRTC VideoSinkInterface
    void OnFrame(const webrtc::VideoFrame& frame) override;

private:
    void InitializeGL();
    void PaintGL();
    void ResizeGL(int w, int h);
    void RenderThreadFunc();
    void RenderFrame(const RenderCommand& cmd);
    void UpdateTexture(const uint8_t* bgra_data, int width, int height);
    void UpdateYUVTextures(const webrtc::I420BufferInterface* buffer);
#ifdef __ANDROID__
    void UpdateAndroidTexture(ANativeWindow* buffer);
#endif
#ifdef __APPLE__
    void UpdateIOSTexture(CVPixelBufferRef pixel_buffer);
#endif
    void Cleanup();

    MediaInfo m_media_info;
    IMainThreadExecutor* m_executor;
    webrtc::VideoTrackInterface* m_video_track = nullptr;
    std::mutex m_mutex;
    std::mutex m_command_mutex;
    std::queue<RenderCommand> m_command_queue;
    std::thread m_render_thread;
    bool m_stop_thread = false;
    std::vector<uint8_t> m_bgra_buffer;
    int m_texture_width = 0;
    int m_texture_height = 0;
    int m_width = 0;
    int m_height = 0;
    bool m_is_rendering = true;
    bool m_use_yuv = true;
    bool m_gl_initialized = false;

    // OpenGL 资源
    GLuint m_program = 0;
    GLuint m_yuv_program = 0;
    GLuint m_vbo = 0;
    GLuint m_ibo = 0;
    GLuint m_texture = 0;
    GLuint m_texture_y = 0;
    GLuint m_texture_u = 0;
    GLuint m_texture_v = 0;
    GLint m_pos_loc = -1;
    GLint m_tex_loc = -1;
    GLint m_yuv_y_loc = -1;
    GLint m_yuv_u_loc = -1;
    GLint m_yuv_v_loc = -1;

#ifdef _WIN32
    HDC m_hdc = nullptr;
    HGLRC m_hglrc = nullptr;
#endif
#ifdef __ANDROID__
    EGLDisplay m_egl_display = EGL_NO_DISPLAY;
    EGLSurface m_egl_surface = EGL_NO_SURFACE;
    EGLContext m_egl_context = EGL_NO_CONTEXT;
#endif
#ifdef __APPLE__
    EAGLContext* m_eagl_context = nullptr;
    GLuint m_framebuffer = 0;
    GLuint m_renderbuffer = 0;
#endif
};

} // namespace p2pms

#endif // __opengl_video_renderer_hpp